package com.atjg.autocat.serialPort

import android.annotation.SuppressLint
import android.content.Context
import com.atjg.autocat.utils.LogUtils
import com.vi.vioserial.COMSerial
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date

class PortUtils {
    private var onSerialPortListenr:OnSerialPortListenr?=null
    private var commandFlag  = ""
   companion object{
       private val BITS_OF_BYTE = 8
       private val POLYNOMIAL = 0xA001
       private val INITIAL_VALUE = 0xFFFF
       private val FF = 0xFF

       private var serialUtils: PortUtils? = null

       private val instance =  COMSerial.instance()
       fun initSerial():PortUtils{
           if (serialUtils == null){
               serialUtils = PortUtils()
           }
           return serialUtils!!
       }

       fun ByteArray.crc16(): ByteArray {
           var res = INITIAL_VALUE
           for (data in this) {
               res = res xor (data.toInt() and FF)
               for (i in 0 until BITS_OF_BYTE) {
                   res = if (res and 0x0001 == 1) res shr 1 xor POLYNOMIAL else res shr 1
               }
           }
           val highByte: Byte = (res and FF).toByte()
           val lowByte: Byte = (res shr 8 and FF).toByte()
           return this.plus(highByte).plus(lowByte)
       }

       fun ByteArray.crc16CCITT(): ByteArray {
           var crc = 0x0000
           for (byte in this) {
               val unsignedByte = byte.toInt() and 0xFF
               crc = crc xor (unsignedByte shl 8)
               repeat(8) {
                   crc = if (crc and 0x8000 != 0) {
                       (crc shl 1) xor 0x1021
                   } else {
                       crc shl 1
                   }
               }
           }
           val highByte: Byte = (crc and FF).toByte()
           val lowByte: Byte = (crc shr 8 and FF).toByte()
           return this.plus(highByte).plus(lowByte)
       }
   }

    fun addPort(filePath:String):Int{
       return instance.addCOM(filePath, 9600)
    }

    fun addDataListener(onSerialPortListenr:OnSerialPortListenr){
        this.onSerialPortListenr = onSerialPortListenr
        instance.addDataListener { com, hexData ->
            onSerialPortListenr.onDataReceived(
                com,
                hexData,
                commandFlag
            )
        }
    }

    fun sendHex(filePath:String,data:String,commandFlag:String){
        this.commandFlag = commandFlag
//        if (commandFlag == "fun-open"){
//            onSerialPortListenr?.onDataSend("0ff61207010101",commandFlag,true)
//            return
//        }
        if(instance.isOpen(filePath)){
            instance.sendHex(filePath,data)
            onSerialPortListenr?.onDataSend(data,commandFlag,true)
        }else{
            onSerialPortListenr?.onDataSend(data,commandFlag,false)
        }
    }

    @OptIn(DelicateCoroutinesApi::class)
    @SuppressLint("SimpleDateFormat")
    fun printData(mContext: Context,it:String){
        GlobalScope.launch(Dispatchers.IO) {
            LogUtils.initLog(mContext).input2File(
                "${
                    SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(
                        Date()
                    )
                } $it \n"
            )
        }
    }
    fun closePort(filePath: String){
        instance?.clearAllDataListener()
        instance?.close(filePath)
    }
    interface OnSerialPortListenr{
        fun onDataReceived(com:String,data:String,commandFlag:String)
        fun onDataSend(data:String,commandFlag:String,isSend:Boolean=true)

    }
}